package pl.put.augrelshooter.connection;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdManager.DiscoveryListener;
import android.net.nsd.NsdManager.RegistrationListener;
import android.net.nsd.NsdManager.ResolveListener;
import android.net.nsd.NsdServiceInfo;
import android.util.Log;

public class NsdHelper {

	public static final String SERVICE_TYPE = "_http._tcp.";
	public static final String TAG = "NsdHelper";
	public static final String GAME_TAG = "AUGS_";
	
	@SuppressWarnings("unused")
	private Context context;
	
	private NsdManager nsdManager;
	private ResolveListener resolveListener;
	private DiscoveryListener discoveryListener;
	private RegistrationListener registrationListener;
	
	private String serviceName = GAME_TAG + "game_name";
	
	Map<String, NsdServiceInfo> foundServices;
	NsdServiceInfo choosenService;
	
	private int isServer;
	
	public NsdHelper (Context context) {
		this.context = context;
		
		choosenService = null;
		foundServices = new HashMap<String, NsdServiceInfo>();
		nsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
	}
	
	public void initializeNsd(int isServer) {
        initializeResolveListener();
        initializeDiscoveryListener();
        initializeRegistrationListener();
        
        this.isServer = isServer;
    }
	
	private void initializeDiscoveryListener() {
		discoveryListener = new DiscoveryListener() {
			
			@Override
			public void onStopDiscoveryFailed(String serviceType, int errorCode) {
				Log.e(TAG, "Discovery failed: Error code:" + errorCode);
				nsdManager.stopServiceDiscovery(this);
			}
			
			@Override
			public void onStartDiscoveryFailed(String serviceType, int errorCode) {
				Log.e(TAG, "Discovery failed: Error code:" + errorCode);
                nsdManager.stopServiceDiscovery(this);				
			}
			
			@Override
			public void onServiceLost(NsdServiceInfo serviceInfo) {
				Log.e(TAG, "Service lost " + serviceInfo);		
				foundServices.remove(serviceInfo.getServiceName());
			}
			
			@Override
			public void onServiceFound(NsdServiceInfo serviceInfo) {
				Log.d(TAG, "Service discovery success" + serviceInfo);
                if (!serviceInfo.getServiceType().equals(SERVICE_TYPE)) {
                    Log.d(TAG, "Unknown Service Type: " + serviceInfo.getServiceType());
                } else if (serviceInfo.getServiceName().equals(serviceName)) {
                    Log.d(TAG, "Same machine: " + serviceName);
                } else if (serviceInfo.getServiceName().contains(GAME_TAG)){                	
                	if (foundServices.containsKey(serviceInfo.getServiceName())) {
                        Log.d(TAG, "Service already registered.");
                        return;
                    }
                	foundServices.put(serviceInfo.getServiceName(), serviceInfo);
                }
			}
			
			@Override
			public void onDiscoveryStopped(String serviceType) {
				Log.i(TAG, "Discovery stopped: " + serviceType);
				
			}
			
			@Override
			public void onDiscoveryStarted(String serviceType) {
				Log.d(TAG, "Service discovery started");				
			}
		};
	}
	
	private void initializeResolveListener() {
		resolveListener = new ResolveListener() {
			
			@Override
			public void onServiceResolved(NsdServiceInfo serviceInfo) {
				Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
                
                choosenService = serviceInfo;
			}
			
			@Override
			public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
				Log.e(TAG, "Resolve failed" + errorCode);				
			}
		};
	}
	
	private void initializeRegistrationListener() {
		registrationListener = new RegistrationListener() {
			
			@Override
			public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
				Log.e(TAG, "Unregistration failed" + errorCode);				
			}
			
			@Override
			public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
				Log.e(TAG, "Service unregistered" + serviceInfo);				
			}
			
			@Override
			public void onServiceRegistered(NsdServiceInfo serviceInfo) {
				serviceName = serviceInfo.getServiceName();
				Log.e(TAG, "Service registered" + serviceInfo);
			}
			
			@Override
			public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
				Log.e(TAG, "Registration failed" + errorCode);
			}
		};
	}
	
	//FIX: obslusga portu z parametru
	public void registerService(String gameName, int port) {
		NsdServiceInfo serviceInfo = new NsdServiceInfo();
		/*port = 1337;
		
		try {
			ServerSocket socket = new ServerSocket(0);
			port = socket.getLocalPort();
		} catch (IOException e) {
			e.printStackTrace();
		}*/
		
		Log.e(TAG, "Port = " + port);
		
		serviceInfo.setPort(port);
		serviceInfo.setServiceName(GAME_TAG + gameName);
		serviceInfo.setServiceType(SERVICE_TYPE);
		
		nsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener);
	}
	
	public void discoverServices() {
		nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener);
	}
	
	public void stopDiscovery() {
        nsdManager.stopServiceDiscovery(discoveryListener);
    }
	
	public void resolveService(NsdServiceInfo service) {
		nsdManager.resolveService(service, resolveListener);
	}

    public Map<String, NsdServiceInfo> getDiscoveredServices() {
        return foundServices;
    }
    
    public NsdServiceInfo getChoosenService() {
    	return choosenService;
    }
    
    public void tearDown() {
    	if (isServer == 1)
    		nsdManager.unregisterService(registrationListener);
    	else
    		nsdManager.stopServiceDiscovery(discoveryListener);
    }
	
}
